package top.oneit.jdownload.controller.dialog;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXTextField;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Popup;
import javafx.stage.Stage;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Headers;
import org.controlsfx.control.MaskerPane;
import top.oneit.jdownload.component.JToast;
import top.oneit.jdownload.constants.JConstants;
import top.oneit.jdownload.constants.RequestMethod;
import top.oneit.jdownload.controller.BaseInitializable;
import top.oneit.jdownload.data.dao.DownloadHistoryDao;
import top.oneit.jdownload.data.dao.DownloadParamDao;
import top.oneit.jdownload.data.entity.DownloadHistory;
import top.oneit.jdownload.data.entity.DownloadParam;
import top.oneit.jdownload.stages.dialog.SelectSavePosition;
import top.oneit.jdownload.utils.BaseUtils;
import top.oneit.jdownload.utils.HttpUtils;
import top.oneit.jdownload.utils.XmlUtils;

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeoutException;

@Slf4j
public class AddDownloadController extends BaseInitializable {
    @FXML
    private JFXCheckBox GET, POST, checkBody, checkHeader;
    @FXML
    private JFXButton confirm, cancel;
    @FXML
    private JFXTextField url;
    public VBox requestParam;
    public TextArea taBody;
    public Button history;

    // 遮罩
    @FXML
    private MaskerPane maskerPane;


    @Override
    public void initialize(URL location, ResourceBundle resources) {
        GET.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!BaseUtils.repeatClickChecking())
                    return;
                if (newValue) {
                    POST.setSelected(false);
                } else if (!POST.isSelected()) {
                    GET.setSelected(true);
                }
                if (checkBody.isSelected()) {
                    checkBody.setSelected(false);
                    taBody.setVisible(false);
                    taBody.setManaged(false);
                }
            }
        });
        POST.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!BaseUtils.repeatClickChecking())
                    return;
                if (newValue) {
                    GET.setSelected(false);
                } else if (!GET.isSelected()) {
                    POST.setSelected(true);
                }
            }
        });

        // 回显历史数据
        List<DownloadHistory> history = DownloadHistoryDao.getHistory();
        if (CollUtil.isNotEmpty(history)) {
            url.setText(history.get(0).getUrl());
        }

        confirm.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (!BaseUtils.repeatClickChecking())
                    return;
                String downloadUrl = url.getText();
                if (StrUtil.isBlank(downloadUrl)) {
                    url.validate();
                    return;
                } else if (!downloadUrl.startsWith("http")) {
                    downloadUrl = "http://" + downloadUrl;
                }
                if (downloadUrl.length() > 1024) {
                    // url太长
                    new JToast().show("url太长，不能超过1024个字符，请独立添加参数", (Stage) GET.getScene().getWindow());
                    return;
                }

                if (StrUtil.isNotBlank(taBody.getText())) {
                    try {
                        JSONObject.parse(taBody.getText());
                    } catch (Exception e) {
                        new JToast().show("请求体不符合json格式！", (Stage) GET.getScene().getWindow());
                        return;
                    }
                }

                if (maskerPane.isVisible()) {
                    return;
                }

                // 进入保存页面动作
                downloadAction(downloadUrl);
                // new JToast().show("加载失败！asdf", (Stage) GET.getScene().getWindow());
            }
        });
        cancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (!BaseUtils.repeatClickChecking())
                    return;
                free();
            }
        });

        url.focusedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!newValue) {
                    url.validate();
                }
            }
        });

        taBody.setVisible(false);
        taBody.setManaged(false);


        loadHeaderSelect(requestParam, false);
        checkBody.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!BaseUtils.repeatClickChecking())
                    return;
                if (newValue && !POST.isSelected()) {
                    new JToast().show("只能在POST请求中使用请求体", POST);
                    checkBody.setSelected(false);
                    return;
                }
                taBody.setVisible(newValue);
                taBody.setManaged(newValue);
            }
        });

        checkHeader.selectedProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if (!BaseUtils.repeatClickChecking())
                    return;
                loadHeaderSelect(requestParam, newValue);
            }
        });

        this.history.setOnAction(event -> clickHistory());
    }

    private void downloadAction(String downloadUrl) {
        maskerPane.setVisible(true);
        // 保存历史
        DownloadHistory history = new DownloadHistory();
        history.setUrl(downloadUrl);
        history.setStatus(JConstants.HISTORY_ADD);
        // 参数
        Map<String, String> headerMap = getHeader();
        DownloadParam param = new DownloadParam();
        param.setHeader(checkHeader.isSelected() && !headerMap.isEmpty() ? JSONObject.toJSONString(headerMap) : null);
        param.setBody(checkBody.isSelected() && StrUtil.isNotBlank(taBody.getText()) ? taBody.getText() : null);
        DownloadParamDao.save(param);
        history.setDownloadParam(param);
        DownloadHistoryDao.save(history);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Headers header;
                try {
                    header = HttpUtils.getHeader(downloadUrl,
                            RequestMethod.HEAD,
                            headerMap,
                            checkBody.isSelected() ? taBody.getText() : null);
                } catch (Exception e) {
                    if (e instanceof SocketTimeoutException) {
                        System.out.println("连接超时！SocketTimeoutException");
                    } else if (e instanceof TimeoutException) {
                        System.out.println("连接超时！TimeoutException");
                    }
                    log.warn("解析下载请求异常！", e);
                    history.setStatus(JConstants.HISTORY_ADD_EXCEPTION);
                    history.setRemarks("解析下载请求异常：" + e.getMessage());
                    DownloadHistoryDao.save(history);
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            maskerPane.setVisible(false);
                            if (e instanceof ConnectException)
                                new JToast().show("无法连接到：" + downloadUrl, confirm);
                            else {
                                new JToast().show(e.getMessage(), confirm);
                            }
                        }
                    });
                    return;
                }

                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        Map<String, List<String>> responseHeader = header.toMultimap();
                        List<String> list = new ArrayList<>(1);
                        list.add(url.getText());
                        responseHeader.put("url", list);
                        maskerPane.setVisible(false);// 关闭遮罩
                        // 进入保存位置
                        new SelectSavePosition(responseHeader, history);
                    }
                });
            }
        }).start();
    }

    private Map<String, String> getHeader() {
        Map<String, String> map = new HashMap<>();
        // hBox
        ObservableList<Node> children = requestParam.getChildren();
        for (Node node : children) {
            if (node instanceof HBox) {
                HBox box = (HBox) node;
                TextField key = (TextField) box.lookup("key");
                TextField value = (TextField) box.lookup("value");
                if (key == null || StrUtil.isBlank(key.getText())) {
                    continue;
                }
                map.put(key.getText(), value.getText());
            }
        }
        return map;
    }

    /**
     * 加载请求头
     */
    private void loadHeaderSelect(VBox requestParam, boolean initVisible) {
        ObservableList<Node> children = requestParam.getChildren();
        if (checkHeader.isSelected() && children.size() == 1 && children.get(0) instanceof TextArea) {
            HBox loadOne = XmlUtils.loadXML("/fxml/dialog/component/header-item.fxml");// 为了加速加载
            requestParam.getChildren().add(children.size() - 1, loadOne);
            return;
        }
        for (Node node : children) {
            if (node instanceof TextArea) {
                continue;
            }
            // 隐藏
            HBox box = (HBox) node;
            if (!box.getId().startsWith("headerHBox")) {
                continue;
            }
            box.setVisible(initVisible ? true : false);
            box.setManaged(initVisible ? true : false);
        }
    }

    private void free() {
        Stage stage = (Stage) cancel.getScene().getWindow();
        stage.close();
    }

    private void clickHistory() {
        Popup popup = new Popup();
        popup.setAutoFix(true);
        popup.setAutoHide(false);

        Button close = new Button("关闭");
        close.setFont(new Font(16.0));
        close.setOnAction(e -> popup.hide());
        ListView<String> list = new ListView<>();
        ObservableList<String> items = FXCollections.observableArrayList();
        List<DownloadHistory> his = DownloadHistoryDao.getHistory(40);
        Set<String> set = new HashSet<>();
        his.forEach(e -> set.add(e.getUrl()));
        set.forEach(e -> items.add(e));
        list.setItems(items);
        list.setMaxHeight(600);
        list.setPrefWidth(600);
        list.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                MultipleSelectionModel<String> selectionModel = list.getSelectionModel();
                String selectedItem = selectionModel.getSelectedItem();
                url.setText(selectedItem);
                popup.hide();
            }
        });
        list.getSelectionModel().selectionModeProperty().addListener(new ChangeListener<SelectionMode>() {
            @Override
            public void changed(ObservableValue<? extends SelectionMode> observable, SelectionMode oldValue, SelectionMode newValue) {
                System.out.println(newValue);
            }
        });

        popup.getContent().add(new VBox(list, close));
        popup.show(history.getScene().getWindow());
    }
}
